package com.yexx.starter.optms.idempotent.keygen.impl;

import com.google.common.base.Joiner;
import com.yexx.starter.optms.idempotent.IdempotentProperties;
import com.yexx.starter.optms.idempotent.annotation.Idempotent;
import com.yexx.starter.optms.idempotent.keygen.LockKeyGenerator;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.*;

/**
 * description:基于header机制生成锁的可以
 *
 * @author: zuomin (myleszelic@outlook.com)
 * @date 2022/06/01:22:49
 */
public class HeaderLockKeyResolver implements LockKeyGenerator {

    private final IdempotentProperties idempotentProperties;

    public HeaderLockKeyResolver(IdempotentProperties idempotentProperties) {
        this.idempotentProperties = idempotentProperties;
    }

    @Override
    public String resolver(Idempotent idempotent, HttpServletRequest request, HttpServletResponse response, HandlerMethod method) {
        String lockKey = null;
        if (StringUtils.hasText(idempotentProperties.getDefaultHeaderLockKey())) {
            lockKey = request.getHeader(idempotentProperties.getDefaultHeaderLockKey());
        }
        if (!StringUtils.hasText(lockKey)) {
            lockKey = NOT_FOUND;
        }
        return String.format("%s:%s", request.getRequestURI(), lockKey);
    }

    private String assembleParam(HttpServletRequest request) {
        Map<String, String> paramMap = new HashMap<>(1 << 2);
        // url param
        assembleUrlParam(request, paramMap);
        // post param
        assembleBodyParam(request, paramMap);
        return sortByDict(paramMap);
    }

    private void assembleBodyParam(HttpServletRequest request, Map<String, String> paramMap) {
        boolean multipartContent = ServletFileUpload.isMultipartContent(request);
        if (multipartContent) {
            paramMap.put("type", "multipartFile");
            return;
        }
        StringBuilder data = new StringBuilder();
        String line;
        BufferedReader reader;
        try {
            reader = request.getReader();
            while (null != (line = reader.readLine())) {
                data.append(line);
            }
        } catch (IOException e) {
            paramMap.put("body", "io read error");
        }
        if(data.length() == 0) {
            return;
        }
        String dataStr = data.toString();
        if (dataStr.length() > 1 << 10) {
            dataStr = dataStr.substring(0, 1 << 10 - 1);
        }
        paramMap.put("body", dataStr);
    }

    private void assembleUrlParam(HttpServletRequest request, Map<String, String> paramMap) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        Map<String, String> urlParam = new HashMap<>();
        if(CollectionUtils.isEmpty(parameterMap)) {
            for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                String key = entry.getKey();
                String[] value = entry.getValue();
                if(value != null && value.length > 0) {
                    urlParam.put(key, value[0]);
                }
            }
            String urlParamStr = sortByDict(urlParam);
            paramMap.put("param", urlParamStr);
        }
    }

    public String sortByDict(Map<String, String> paramMap) {
        if (CollectionUtils.isEmpty(paramMap)) {
            return "";
        }
        List<String> keySet = new ArrayList<>(paramMap.keySet());
        Collections.sort(keySet);
        List<String> kvs = new ArrayList<>(1 << 2);
        for (String key : keySet) {
            String value = paramMap.get(key);
            if (value != null) {
                kvs.add(key + "=" + value);
            }
        }
        return Joiner.on("&").join(kvs);
    }
}
